package com.deer.wms.ware.task.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.deer.wms.base.system.service.AreaInfoService;
import com.deer.wms.base.system.service.CellInfoService;
import com.deer.wms.busine.tactic.model.TurnoverTacticDetail;
import com.deer.wms.busine.tactic.model.TurnoverTacticDetailCriteria;
import com.deer.wms.busine.tactic.service.PickTacticService;
import com.deer.wms.busine.tactic.service.TurnoverTacticDetailService;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.inventory.constant.InventoryConstant;
import com.deer.wms.inventory.model.Inventory.Inventory;
import com.deer.wms.inventory.model.Inventory.InventoryCriteria;
import com.deer.wms.inventory.model.Inventory.InventorySelectDto;
import com.deer.wms.inventory.model.Inventory.InventoryTransact;
import com.deer.wms.inventory.service.InventoryService;
import com.deer.wms.inventory.service.InventoryTransactService;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.BeanUtils;
import com.deer.wms.system.manage.constant.SystemManageConstant;
import com.deer.wms.system.manage.model.user.UserInfo;
import com.deer.wms.system.manage.model.ware.AreaUser;
import com.deer.wms.system.manage.service.AreaUserService;
import com.deer.wms.system.manage.service.CellLedService;
import com.deer.wms.system.manage.service.CodeRuleService;
import com.deer.wms.ware.task.model.pushErp.StrategyErpService;
import com.deer.wms.ware.task.constant.WareTaskConstant;
import com.deer.wms.ware.task.dao.PickTaskMapper;
import com.deer.wms.ware.task.model.SO.SoDetail;
import com.deer.wms.ware.task.model.SO.SoDetailDto;
import com.deer.wms.ware.task.model.SO.SoMaster;
import com.deer.wms.ware.task.model.Wave.WaveDetail;
import com.deer.wms.ware.task.model.Wave.WaveMaster;
import com.deer.wms.ware.task.model.out.OutDetail;
import com.deer.wms.ware.task.model.out.OutMaster;
import com.deer.wms.ware.task.model.pickTask.PickTask;
import com.deer.wms.ware.task.model.pickTask.PickTaskCriteria;
import com.deer.wms.ware.task.model.pickTask.PickTaskDto;
import com.deer.wms.ware.task.model.pickTask.SeedingWallAlertInfo;
import com.deer.wms.ware.task.model.pushErp.beasAssist.BaseAssist;
import com.deer.wms.ware.task.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author guo
 * @since 2020/02/02
 */
@Service
@Transactional
public class PickTaskServiceImpl extends SuperServiceImpl<PickTaskMapper, PickTask> implements PickTaskService {

    @Autowired
    private PickTaskMapper pickTaskMapper;
    @Autowired
    private PickTaskService pickTaskService;
    @Autowired
    private CodeRuleService codeRuleService;
    @Autowired
    private PickTacticService pickTacticService;
    @Autowired
    private SoDetailService soDetailService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private InventoryTransactService inventoryTransactService;
    @Autowired
    private SoMasterService soMasterService;
    @Autowired
    private WaveMasterService waveMasterService;
    @Autowired
    private WaveDetailService waveDetailService;
    @Autowired
    private TurnoverTacticDetailService turnoverTacticDetailService;
    @Autowired
    private AreaUserService areaUserService;
    @Autowired
    private AreaInfoService areaInfoService;
    @Autowired
    private OutMasterService outMasterService;
    @Autowired
    private StrategyErpService strategyErpService;
    @Autowired
    private CellLedService cellLedService;

    @Value("${prj.name}")
    private String prjName;

    @Override
    public List<PickTaskDto> findList(PickTaskCriteria criteria) {
        return pickTaskMapper.findList(criteria);
    }

    @Override
    public List<PickTaskDto> findByBillNo(PickTaskCriteria criteria) {
        return pickTaskMapper.findByBillNo(criteria);
    }

    @Override
    public List<PickTaskDto> findByWaveMasterId(PickTaskCriteria criteria) {
        return pickTaskMapper.findByWaveMasterId(criteria);
    }

    @Override
    public List<PickTaskDto> allotTask(PickTaskCriteria criteria) {
        return pickTaskMapper.allotTask(criteria);
    }

    @Override
    public List<PickTaskDto> findFirst(PickTaskCriteria criteria) {
        return pickTaskMapper.findFirst(criteria);
    }

    @Override
    public List<PickTaskDto> findBySo(String soNo) {
        return pickTaskMapper.findBySo(soNo);
    }

    @Override
    public List<PickTaskDto> findByWaveDetail(Integer waveDetailId) {
        return pickTaskMapper.findByWaveDetail(waveDetailId);
    }

    @Override
    public List<SeedingWallAlertInfo> getSeedingWallAlertInfo(PickTaskCriteria criteria) {
        return pickTaskMapper.getSeedingWallAlertInfo(criteria);
    }

    @Override
    public void createPickTask(Integer soType) {
        //Step1.找到所有待分配的SO明细
        List<SoDetailDto> soDetailDtos = soDetailService.findUndistributedSoDetail(soType);
        //库位id
        Set<Integer> wareIds = soDetailDtos.stream().map(SoDetailDto::getWareId).collect(Collectors.toSet());
        //找到所有待分配id
        Set<String> sobillNos = soDetailDtos.stream().map(SoDetailDto::getBillNo).collect(Collectors.toSet());
        //获取所有soMaster
        List<SoMaster> soMasterList = soMasterService.list(new QueryWrapper<SoMaster>()
                .in("bill_no", sobillNos)
        );
        Map<String, List<SoMaster>> soMasterMap = soMasterList.stream().collect(Collectors.groupingBy(SoMaster::getBillNo));
        //货主Id
        Set<Integer> organizationSet = soDetailDtos.stream().map(SoDetailDto::getOrganizationId).collect(Collectors.toSet());
        //物料编码
        Set<String> codeSet = soDetailDtos.stream().map(SoDetailDto::getItemCode).collect(Collectors.toSet());
        InventoryCriteria inventoryCriteria = new InventoryCriteria();
        //物料编码
        inventoryCriteria.setItemCodes(codeSet);
        //code
        inventoryCriteria.setParam(1003);
        //货主id
        inventoryCriteria.setOrganizationSet(organizationSet);
        //明细id
        inventoryCriteria.setWareIds(wareIds);
        List<InventorySelectDto> canBeOutOfStock = inventoryService.findCanBeOutOfStock(inventoryCriteria);
        List<SoMaster> masterList = new ArrayList<>();
        if (soDetailDtos.size() > 0) {
            soDetailDtos:
            for (SoDetailDto soDetail : soDetailDtos) {
                List<InventorySelectDto> inventorySelectDtos = canBeOutOfStock.stream().filter(
                        item ->
                                item.getItemCode().equals(soDetail.getItemCode()) &&
                                        item.getWareId().equals(soDetail.getWareId()) &&
                                        item.getOrganizationId().equals(soDetail.getOrganizationId())
                ).collect(Collectors.toList());

                //Step4.判断是否足够分配
                // 如果库存不够 直接不给分配
                Double totalCanBeQuantity = 0.0;
                for (InventorySelectDto inventorySelectDto : inventorySelectDtos) {
                    totalCanBeQuantity += inventorySelectDto.getQuantity() - inventorySelectDto.getAllotQuantity() - inventorySelectDto.getFreezeQuantity();
                }
                if (totalCanBeQuantity < soDetail.getOrderQuantity() - soDetail.getAllottedQuantity()) {
                    if (ObjectUtil.isNotEmpty(soMasterMap.get(soDetail.getBillNo()))) {
                        SoMaster soMaster = new SoMaster();
                        soMaster = soMasterMap.get(soDetail.getBillNo()).get(0);
                        soMaster.setState(WareTaskConstant.SO_STATE_OUTOFSTOCK);
                        masterList.add(soMaster);
                    }
//                    SoMaster soMaster = soMasterService.findBy("bill_no", soDetail.getBillNo());

//                    soMasterService.updateById(soMaster);
                    //跳出循环
                    continue;
                }
                //Step5.创建拣货任务
                this.createPickTask(soDetail, inventorySelectDtos);
            }
        }
        soMasterService.updateBatchById(masterList);
        //Step6.FIXME:合并拣货任务  波次
        List<PickTaskDto> mergePickTasks = pickTaskMapper.mergeTask();
        mergePickTasks.forEach(item -> {
            List<PickTask> list = pickTaskMapper.findMergeTask(item);
            // 插入合并任务
            item.setPickTaskId(null);
            Double quantity = 0.0;
            for (PickTask pickTask : list) {
                quantity += pickTask.getPickQuantity();
            }

            item.setPickQuantity(quantity);
            item.setIsParent(1);
            save(item);

            for (PickTask pickTask : list) {
                pickTask.setParentTaskId(item.getPickTaskId());
                pickTask.setState(WareTaskConstant.PICK_STATE_MERGED);
                updateById(pickTask);
            }
            // 关联合并任务ID，并状态改为已合并
            //pickTaskMapper.updateChildTasks(item);
        });

        //FIXME:爆款产品，从验收位置直接生成拣货任务
//        List<Inventory> inventories = inventoryService.findBaoKuan(wareId);
//        for (Inventory in:inventories
//             ) {
//            createBaoKuanPickTask(in);
//        }
    }

    @Override
    public void createPickTask(List<WaveDetail> waveDetailList, UserInfo currentUser) {
        List<PickTask> pickTaskList = new ArrayList<>();

        for (WaveDetail waveDetail : waveDetailList) {
            //Step1.拼接条件(库区，物料)  找到可用容器库存 --这里的库存就是最细的粒度，后续分配的时候也是按容器来分配
            InventoryCriteria inventoryCriteria = new InventoryCriteria();
            inventoryCriteria.setWareId(waveDetail.getWareId());
            inventoryCriteria.setItemCode(waveDetail.getItemCode());

            AreaUser areaUser = areaUserService.getById(waveDetail.getPickUserId());
            if (ObjectUtil.isNotNull(areaUser)) {
                inventoryCriteria.setAreaCode(areaInfoService.getById(areaUser.getAreaId()).getAreaCode());
            }
            inventoryCriteria.setOrganizationId(-1); //自有库存
            //FIXME：里面涉及到周转规则，规则写死  仅按批次排序先进先出
            List<InventorySelectDto> inventoryDtos = inventoryService.findCanBeOutOfStock(inventoryCriteria);

            //Step2.生成拣货任务
            double remainAllotQty;
            //有预分配数量则取预分配数量，没有则全部分配
            if (ObjectUtil.isNotNull(waveDetail.getPreAllottedQuantity()) && waveDetail.getPreAllottedQuantity() > 0) {
                remainAllotQty = waveDetail.getPreAllottedQuantity();
            } else {
                remainAllotQty = waveDetail.getQuantity() - waveDetail.getAllottedQuantity();
            }
            for (InventorySelectDto inv : inventoryDtos) {
                //Step2.1新建拣货任务  根据波次明细初始化
                PickTask pickTask = new PickTask(waveDetail);
                //记录库位，容器，批次
                pickTask.setBoxCode(inv.getBoxCode());
                pickTask.setAreaCode(inv.getAreaCode());
                pickTask.setAreaName(inv.getAreaName());
                pickTask.setCellCode(inv.getCellCode());
                pickTask.setCellName(inv.getCellName());
                pickTask.setBatchId(inv.getBatchId());
                pickTask.setBatchName(inv.getBatchName());
                pickTask.setPickTaskCode(codeRuleService.generateCode(SystemManageConstant.CODE_RULE_PICK));
                //遍历可用库存，分配可用数量 (引申：对于复杂场景，这里可用动态规划的算法)
                double canBeQuantity = inv.getQuantity() - inv.getAllotQuantity() - inv.getFreezeQuantity();
                if (canBeQuantity >= remainAllotQty) {
                    //1)可分配数量 大于出库任务明细待分配数量 出库任务明细分配完毕
                    pickTask.setPickQuantity(remainAllotQty);
                    waveDetail.setPickUserId(currentUser.getUserId());
                    waveDetail.setPickUserName(currentUser.getUserName());
                    waveDetail.setAllottedTime(LocalDateTime.now());
                    //记录波次明细的已分配数量 记录状态为已分配
                    waveDetail.setAllottedQuantity(waveDetail.getAllottedQuantity() + pickTask.getPickQuantity());
                    if (ObjectUtil.isNotNull(waveDetail.getPreAllottedQuantity()) && waveDetail.getPreAllottedQuantity() > 0) {
                        waveDetail.setPreAllottedQuantity(0.0);
                    }

                    //需要记录库存的已分配数量
                    inv.setAllotQuantity(inv.getAllotQuantity() + pickTask.getPickQuantity());
                    inv.setTransRatio(1.0);
                    inventoryService.updateById(inv);
                    pickTaskList.add(pickTask);
                    //分配完成直接跳出循环
                    //记录状态
                    if (ObjectUtil.equal(waveDetail.getQuantity(), waveDetail.getAllottedQuantity())) {
                        waveDetail.setState(WareTaskConstant.WAVE_STATE_ALL_ALOT);
                    } else {
                        waveDetail.setState(WareTaskConstant.WAVE_STATE_PICKING);
                    }
                    break;
                } else {
                    //2)可分配数量不够完全分配  则将可分配数量全部分配出去
                    pickTask.setPickQuantity(canBeQuantity);
                    waveDetail.setPickUserId(currentUser.getUserId());
                    waveDetail.setPickUserName(currentUser.getUserName());
                    waveDetail.setAllottedTime(LocalDateTime.now());

                    waveDetail.setAllottedQuantity(waveDetail.getAllottedQuantity() + canBeQuantity);
                    if (ObjectUtil.isNotNull(waveDetail.getPreAllottedQuantity()) && waveDetail.getPreAllottedQuantity() > 0) {
                        waveDetail.setPreAllottedQuantity(waveDetail.getPreAllottedQuantity() - canBeQuantity);
                    }

                    inv.setAllotQuantity(inv.getAllotQuantity() + canBeQuantity);
                    inv.setTransRatio(1.0);
                    inventoryService.updateById(inv);
                    pickTaskList.add(pickTask);

                    remainAllotQty -= canBeQuantity;
                }

                //记录状态
                if (ObjectUtil.equal(waveDetail.getQuantity(), waveDetail.getAllottedQuantity())) {
                    waveDetail.setState(WareTaskConstant.WAVE_STATE_ALL_ALOT);
                } else {
                    waveDetail.setState(WareTaskConstant.WAVE_STATE_PICKING);
                }
            }
        }

        //保存生成的拣货任务
        pickTaskService.saveBatch(pickTaskList);
        //更新波次明细状态 和 已分配数量
        waveDetailService.updateBatchById(waveDetailList);
        //更新波次状态
        WaveMaster waveMaster = waveMasterService.getById(waveDetailList.get(0).getWaveMasterId());
        waveMaster.setState(WareTaskConstant.WAVE_STATE_PICKING);
        waveMasterService.updateById(waveMaster);
    }

    @Override
    public void createPickTask(SoMaster soMaster, CurrentUser currentUser) {
        List<SoDetail> soDetails = soDetailService.getListByField("bill_no", soMaster.getBillNo());

        for (SoDetail soDetail : soDetails) {
            //只需要对未完全分配的进行拣货推荐：计划数大于已分配数
            if (soDetail.getOrderQuantity() > soDetail.getAllottedQuantity()) {
                //创建拣货任务
                this.createPickTask(soMaster, soDetail);
            }
        }
    }

    @Override
    public void createPickTask(SoDetail soDetail, CurrentUser currentUser) {
        SoMaster soMaster = soMasterService.getById(soDetail.getSoMasterId());
        //只需要对未完全分配的进行拣货推荐：计划数大于已分配数
        if (soDetail.getOrderQuantity() > soDetail.getAllottedQuantity()) {
            //创建拣货任务
            this.createPickTask(soMaster, soDetail);
        }
    }

    @Override
    public void cancelPickTask(PickTask pickTask) {
        double unPickQty = pickTask.getPickQuantity() - pickTask.getReviewQuantity();
        SoDetail soDetail = soDetailService.getById(pickTask.getSoDetailId());
        soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() - unPickQty);
        soDetailService.updateById(soDetail);
        pickTask.setState(WareTaskConstant.PICK_STATE_CANCELED);
        pickTaskService.updateById(pickTask);
        Inventory inventory = inventoryService.getById(pickTask.getInventoryId());
        /**
         * 涉及到转换率
         */
//            double quantity = MyUtils.calculateMultiplication(inventory.getPackDetailId(), pickTask.getPackDetailId(), pickTask.getPickQuantity(), pickTask.getTransRatio());
        if(ObjectUtil.isNotNull(inventory)){
            inventory.setAllotQuantity(inventory.getAllotQuantity() - unPickQty);
            inventoryService.updateById(inventory);
        }
    }


    /**
     * 根据可用库存，分配生成拣货任务
     *
     * @param soDetail      SO明细
     * @param soDetail 可用库存
     */
    private void createPickTask(SoMaster soMaster, SoDetail soDetail) {
        //Step1.根据条件查询库存
        InventoryCriteria criteria = new InventoryCriteria();
        criteria.setWareId(soMaster.getWareId());
        criteria.setItemCode(soDetail.getItemCode());
        //可能还有其他的条件
        // ...批次  工单号等等
        List<InventorySelectDto> inventoryDtos = inventoryService.findCanBeOutOfStock(criteria);
        if (CollectionUtil.isEmpty(inventoryDtos)) {
            return;
        }

        //Step2.对可用库存进行分配
        for (InventorySelectDto invDto : inventoryDtos) {
            //新建拣货任务
            PickTask pickTask = new PickTask(soMaster, soDetail, invDto);
            pickTask.setPickTaskCode(codeRuleService.generateCodeByRedis(SystemManageConstant.CODE_RULE_PICK));

            //[可用的库存数量]
            double canBeQty = invDto.getQuantity() - invDto.getAllotQuantity() - invDto.getFreezeQuantity();
            //[SO待分配的数量]
            double remainAllotQty = soDetail.getOrderQuantity() - soDetail.getAllottedQuantity();
            //判断可分配数量
            if (canBeQty >= remainAllotQty) {
                //1)可用库存大于待分配数量 出库任务明细分配完毕
                pickTask.setPickQuantity(remainAllotQty);
                //记录库存已分配数量
                invDto.setAllotQuantity(invDto.getAllotQuantity() + pickTask.getPickQuantity());
                //记录出库任务的已分配数量
                soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() + pickTask.getPickQuantity());
                invDto.setTransRatio(1.0);

                inventoryService.updateById(invDto);
                save(pickTask);
                soDetailService.updateById(soDetail);
                break;
            } else {
                //2)可用库存数量不够完全分配  全部分配出去
                if (canBeQty > 0) {
                    pickTask.setPickQuantity(canBeQty);
                    invDto.setAllotQuantity(invDto.getAllotQuantity() + canBeQty);
                    soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() + canBeQty);
                    invDto.setTransRatio(1.0);
                    inventoryService.updateById(invDto);
                    save(pickTask);
                    soDetailService.updateById(soDetail);
                }
            }
        }

        //Step3.更新来源单据状态
        if (ObjectUtil.equal(soMaster.getState(), WareTaskConstant.OUT_STATE_INIT)) {
            soMaster.setState(WareTaskConstant.OUT_STATE_DOING);
            soMasterService.updateById(soMaster);
        }
        if (ObjectUtil.equal(soMaster.getState(), WareTaskConstant.OUT_STATE_INIT)) {
            soDetail.setState(WareTaskConstant.OUT_STATE_DOING);
            soDetailService.updateById(soDetail);
        }
    }

    private void updateSoAllotState(SoMaster soMaster, SoDetail soDetail) {
        //回写SO状态
        List<SoDetail> list = soDetailService.findByBillNo(soDetail.getBillNo());
        boolean isAllAllot = true;
        for (SoDetail detail : list) {
            if (detail.getAllottedQuantity() > 0) {
                //部分分配 缺货
                soMaster.setState(WareTaskConstant.SO_STATE_OUTOFSTOCK);
            }
            if (detail.getOrderQuantity() > detail.getAllottedQuantity()) {
                isAllAllot = false;
                break;
            }
        }
        if (isAllAllot) {
            soMaster.setState(WareTaskConstant.SO_STATE_ASSIGNED);
        }
        soMasterService.updateById(soMaster);
    }

    /**
     * 处理库存周转规则 待完成
     *
     * @param soDetail
     */
    private String extracted(SoDetailDto soDetail) {
        StringBuffer sort = new StringBuffer();
        //找到库存周转规则，没有则取系统默认周转规则
        String turnoverTacticCode = soDetail.getTurnoverTacticCode();
        if (turnoverTacticCode == null) {
            turnoverTacticCode = "sys_turnover";
        }
        //周转规则
        List<TurnoverTacticDetail> turnoverTacticDetails = turnoverTacticDetailService.findList(new TurnoverTacticDetailCriteria(turnoverTacticCode));
        if (turnoverTacticDetails.size() > 0) {
            for (int i = 0; i < turnoverTacticDetails.size(); i++) {
                TurnoverTacticDetail turnoverTacticDetail = turnoverTacticDetails.get(i);
                if (turnoverTacticDetail.getBatchTacticDetailCode().equals("productDate")) {
                    sort.append("product_date");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("exDate")) {
                    sort.append("ex_date");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("inDate")) {
                    sort.append("in_date");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("supplierCode")) {
                    sort.append("supplier_code");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("supplierBatch")) {
                    sort.append("supplier_batch");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("qcState")) {
                    sort.append("qc_state");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("costPrice")) {
                    sort.append("cost_price");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("salePrice")) {
                    sort.append("sale_price");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("detailNo")) {
                    sort.append("detail_no");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("memo1")) {
                    sort.append("memo1");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("memo2")) {
                    sort.append("memo2");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("memo3")) {
                    sort.append("memo3");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("batchAttribute1")) {
                    sort.append("batch_attribute_1");
                } else if (turnoverTacticDetail.getBatchTacticDetailCode().equals("batchAttribute2")) {
                    sort.append("batch_attribute_2");
                }
                //判断升序或者降序
                if (turnoverTacticDetail.getSort().equals(1)) {
                    sort.append(" asc,");
                } else {
                    sort.append(" desc,");
                }
//                        if((i+1)==turnoverTacticDetails.size()&&sort.length()>0){
//                            sort.substring(0,sort.lastIndexOf(","));
//                        }
            }
        }
        String sortSql = sort.toString();
        sortSql = sortSql.substring(0, sortSql.lastIndexOf(','));
        return sortSql;
    }

    @Autowired
    private CellInfoService cellInfoService;

    @Override
    public void createBaoKuanPickTask(Inventory inventory, Integer acceptRecordId) {

        //Step1.重新生成库存
        Integer inventoryId = inventory.getInventoryId();
        Inventory newInventory = inventory;
        newInventory.setInventoryId(null);
        inventoryService.save(newInventory);

        //准备数据
        String fromCellCode = inventory.getCellCode();
        String toCellCode = cellInfoService.getSysJhCell(inventory.getWareId()); //获取系统内置的集货库位
        Double quantity = inventory.getQuantity();
        Double allotQuantity = 0.0;
        Double dpAllotQuantity = 0.0;


        List<SoDetailDto> soDetailDtos = soDetailService.findBaoKuanByItemCode(inventory.getItemCode(), inventory.getWareId(), inventory.getOrganizationId());
        if (soDetailDtos.size() > 0) {
            for (SoDetailDto soDetail : soDetailDtos) {
                if (soDetail.getSoStructure() > 1) {
                    dpAllotQuantity += soDetail.getOrderQuantity() - soDetail.getAllottedQuantity();
                    continue;
                }
                if (soDetail.getAllottedQuantity() > 0) {
                    dpAllotQuantity += soDetail.getOrderQuantity() - soDetail.getAllottedQuantity();
                    continue;
                }
                if (quantity - allotQuantity - dpAllotQuantity >= soDetail.getOrderQuantity()) {
                    PickTask pickTask = new PickTask(
                            soDetail.getSoDetailId(),
                            soDetail.getSoMasterId(),
                            soDetail.getWareId(),
                            soDetail.getWareName(),
                            soDetail.getOrganizationId(),
                            soDetail.getOrganizationName(),
                            fromCellCode,
                            inventory.getItemCode(),
                            inventory.getItemName(),
                            inventory.getBatchId(),
                            inventory.getBatchName(),
                            inventory.getBoxCode(),
                            inventory.getLpn(),
                            soDetail.getPackDetailId(),
                            soDetail.getPackDescribe(),
                            soDetail.getOrderQuantity(),
                            2,
                            newInventory.getInventoryId(),
                            2,
                            inventory.getImgUrl()
                    );
                    pickTask.setToCellCode(toCellCode);
                    save(pickTask);
                    soDetail.setAllottedQuantity(pickTask.getPickQuantity());
                    soDetail.setPickTransRatio(1.0);
                    soDetail.setPickQuantity(pickTask.getPickQuantity());
                    soDetail.setState(2);
                    soDetailService.updateById(soDetail);
                    SoMaster soMaster = soMasterService.findBy("bill_no", soDetail.getBillNo());
                    soMaster.setState(6); //全部拣货
                    soMasterService.updateById(soMaster);
                    allotQuantity += pickTask.getPickQuantity();
                }
            }
        }
        if (allotQuantity < 0.1) {
            inventoryService.removeById(newInventory.getInventoryId());
            return;
        }


        newInventory.setCellCode(toCellCode);
        //newInventory.setAllotQuantity(allotQuantity);
        newInventory.setQuantity(allotQuantity);
        newInventory.setBaoKuan(acceptRecordId);
        inventoryService.updateById(newInventory);

        if (quantity - allotQuantity < 0.1) {
            inventoryService.removeById(inventoryId);
        } else {
            inventory.setInventoryId(inventoryId);
            inventory.setCellCode(fromCellCode);
            inventory.setQuantity(quantity - allotQuantity);
            inventory.setAllotQuantity(0.0);
            inventory.setBaoKuan(0);
            inventoryService.updateById(inventory);
        }


    }

    @Override
    public List<PickTask> findBySoDetailId(Integer soDetailId) {
        return pickTaskMapper.findBySoDetailId(soDetailId);
    }

    @Override
    public List<PickTaskDto> findBySoMasterId(Integer soMaterId) {
        return pickTaskMapper.findBySoMasterId(soMaterId);
    }

    @Override
    public Integer commitPick(PickTask pickTask, double pickQty, CurrentUser currentUser) {
        //Step1.库存处理
        InventoryTransact inventoryTransact = toStockRequest(pickTask, pickQty, currentUser);
        int ivtId = inventoryTransactService.run(inventoryTransact);

        //Step2.更新拣货任务状态
        pickTask.setPickTime(DateUtil.now());
        pickTask.setPickUserId(currentUser.getUserId());
        pickTask.setPickUserName(currentUser.getUserName());
        pickTask.setToInventoryId(ivtId);
        pickTask.setToBoxCode(inventoryTransact.getToBoxCode());
        //记录已拣货数量，可能分多次拣货
        pickTask.setReviewQuantity(pickTask.getReviewQuantity() + pickQty);
        if (pickTask.getReviewQuantity() >= pickTask.getPickQuantity()) {
            //拣满或者超过都算全部拣货
            pickTask.setState(WareTaskConstant.PICK_STATE_ALLPICK);
        } else {
            pickTask.setState(WareTaskConstant.PICK_STATE_PARTPICK);
        }
        this.updateById(pickTask);

        //Step3.更新SO
        SoDetail soDetail = soDetailService.getById(pickTask.getSoDetailId());
        //拣货数量
        soDetail.setPickQuantity(soDetail.getPickQuantity() + pickQty);
        soDetailService.updateById(soDetail);

        //Step4.生成出库单
        String outBillCode = outMasterService.createOutBill(pickTask, pickQty, currentUser);

        if (ObjectUtil.equal("zp", this.prjName)) {
            OutMaster outMaster = outMasterService.getOneByField("bill_no", outBillCode);
            //拣货即出库
            outMasterService.confirmOutBill(outMaster, currentUser);
        }

        return ivtId;
    }

    @Autowired
    private OutDetailService outDetailService;
    @Autowired
    private PushErpService pushErpService;

    @Override
    public OutMaster pickAndSendOut(List<PickTask> pickTasks, CurrentUser currentUser, Integer erpAreaId) {
        OutMaster outMaster = null;
        List<OutDetail> outDetails = new ArrayList<>();
        SoMaster soMaster = soMasterService.getById(pickTasks.get(0).getSoMasterId());
        Set<SoDetail> soDetails = new HashSet<>();
        int rowNo = 1;
        for (PickTask pickTask : pickTasks) {
            //1.处理拣货任务
            pickTask.setReviewQuantity(pickTask.getPickQuantity());
            pickTask.setSeededQuantity(pickTask.getPickQuantity());
            pickTask.setState(WareTaskConstant.PICK_STATE_OUTED);

            //2.状态修改(拣货任务、出库任务明细、出库任务)
            SoDetail soDetail = soDetailService.getById(pickTask.getSoDetailId());
            soDetail.setPickQuantity(soDetail.getPickQuantity() + pickTask.getSeededQuantity());
            soDetail.setDeliveryQuantity(soDetail.getDeliveryQuantity() + pickTask.getSeededQuantity());
            if (soDetail.getOrderQuantity().equals(soDetail.getDeliveryQuantity())) {
                soDetail.setState(WareTaskConstant.SO_DETAIL_STATE_ALL_SEND);
            }
            soDetails.add(soDetail);

            //3.生成出库单
            if (outMaster == null) {
                outMaster = new OutMaster(soMaster);
                String billNo = codeRuleService.generateCode("OUT");
                outMaster.setBillNo(billNo);
                outMaster.setState(WareTaskConstant.SO_STATE_OUTED);
                outMaster.setCreateUserId(currentUser.getUserId());
                outMaster.setCreateUserName(currentUser.getUserName());
                outMasterService.save(outMaster);
            }
            OutDetail outDetail = new OutDetail();
            BeanUtils.copyProperties(soDetail, outDetail);
            outDetail.setState(WareTaskConstant.SO_DETAIL_STATE_ALL_SEND);
            outDetail.setDetailNo(outMaster.getBillNo() + "-" + rowNo);
            Inventory allotInv = inventoryService.getById(pickTask.getInventoryId());
            outDetail.setBoxCode(allotInv.getBoxCode());
            outDetail.setCellCode(allotInv.getCellCode());
            outDetail.setBatchName(allotInv.getBatchName());
            outDetail.setErpAreaId(allotInv.getErpAreaId());
            rowNo++;
            outDetail.setBillNo(outMaster.getBillNo());
            //数量
            outDetail.setDeliveryQuantity(pickTask.getSeededQuantity());
            outDetails.add(outDetail);
        }
        this.updateBatchById(pickTasks);
        soDetailService.updateBatchById(soDetails);

        outDetailService.saveBatch(outDetails);
        //更新SO FIXME: 转换为公共方法
        Set<Integer> soMasterIds = pickTasks.stream()
                .map(pickTask -> pickTask.getSoMasterId()).collect(Collectors.toSet());
        List<SoMaster> soMasters = soMasterService.listByIds(soMasterIds);
        for (SoMaster master : soMasters) {
            List<SoDetail> details = soDetailService.list(new QueryWrapper<SoDetail>().eq("bill_no", master.getBillNo()));
            List<SoDetail> collect = details.stream()
                    .filter(soDetail -> soDetail.getOrderQuantity() > soDetail.getDeliveryQuantity())
                    .collect(Collectors.toList());
            if (collect.size() == 0) {
                master.setState(WareTaskConstant.SO_STATE_OUTED);
            }
        }
        soMasterService.updateBatchById(soMasters);

        List<InventoryTransact> inventoryTransacts = outDetailService.toStockRequest(outMaster, currentUser);
        inventoryTransacts.forEach(inventoryTransact -> inventoryTransactService.run(inventoryTransact));

        HashSet<OutDetail> outDetailSet = new HashSet<>(outDetails);
//        strategyErpService.resolveSo(soMaster, outDetailSet, baseAssist);
//        OrderToErpBO erpBean = waveDetailService.getErpBean(outDetailSet, outMaster.getBillNo());
//        pushErpService.pushIMBIll(erpBean);
        return outMaster;
    }

    /**
     * 拣货任务生成库存事务
     *
     * @param pickTask    拣货任务
     * @param currentUser 当前用户
     * @return InventoryTransact库存事务
     */
    private InventoryTransact toStockRequest(PickTask pickTask, double pickQty, CurrentUser currentUser) {
        InventoryTransact inventoryTransact = new InventoryTransact();
        //Step1.准备数据
        //仓库
        inventoryTransact.setWareId(pickTask.getWareId());
        inventoryTransact.setWareName(pickTask.getWareName());
        //
        inventoryTransact.setFromInventoryId(pickTask.getInventoryId());
        //货主
        inventoryTransact.setFromOrganizationId(pickTask.getOrganizationId());
        inventoryTransact.setFromOrganizationName(pickTask.getOrganizationName());
        inventoryTransact.setToOrganizationId(pickTask.getOrganizationId());
        inventoryTransact.setToOrganizationName(pickTask.getOrganizationName());
        //库位
        inventoryTransact.setFromCellCode(pickTask.getCellCode());
        inventoryTransact.setToCellCode(pickTask.getToCellCode());
        //容器
        inventoryTransact.setFromBoxCode(pickTask.getBoxCode());
        Inventory inventory = inventoryService.getById(pickTask.getInventoryId());
        if (inventory.getQuantity().equals(pickQty)) {
            inventoryTransact.setToBoxCode(pickTask.getToBoxCode());
        } else {
            String lpn = codeRuleService.generateCodeByRedis(SystemManageConstant.CODE_RULE_TN);
            inventoryTransact.setToBoxCode(lpn);
        }

        //物料
        inventoryTransact.setItemCode(pickTask.getItemCode());
        inventoryTransact.setItemName(pickTask.getItemName());
        inventoryTransact.setImgUrl(pickTask.getImgUrl());
        //批次
        inventoryTransact.setFromBatchId(pickTask.getBatchId());
        inventoryTransact.setFromBatchName(pickTask.getBatchName());
        inventoryTransact.setToBatchId(pickTask.getBatchId());
        inventoryTransact.setToBatchName(pickTask.getBatchName());

        //数量
        inventoryTransact.setFromQuantity(pickTask.getPickQuantity());
        inventoryTransact.setToQuantity(pickQty);
        //包装 转换率
        inventoryTransact.setFromPackDetailId(pickTask.getPackDetailId());
        inventoryTransact.setFromPackDescribe(pickTask.getPackDescribe());
        inventoryTransact.setToPackDetailId(pickTask.getPackDetailId());
        inventoryTransact.setToPackDescribe(pickTask.getPackDescribe());
        inventoryTransact.setFromTransRatio(1.0);
        inventoryTransact.setToTransRatio(1.0);
        //创建人 时间
        inventoryTransact.setCreateUserId(currentUser.getUserId());
        inventoryTransact.setCreateUserName(currentUser.getUserName());
        inventoryTransact.setCreateTime(DateUtil.now());
        //事务类型 这个字段很重要
//        if (StringUtils.isEmpty(pickTask.getToBoxCode())) {
        //整箱拣货
        inventoryTransact.setTransactType(InventoryConstant.TRANSACT_TYPE_PICK);
//        } else {
//            inventoryTransact.setTransactType(InventoryConstant.TRANSACT_TYPE_PICK2);
//        }
        //来源单据号
        //记录单据号
//        if(ObjectUtil.isNotNull(pickTask.getSoMasterId())){
//            SoMaster soMaster = soMasterService.getById(pickTask.getSoMasterId());
//            inventoryTransact.setBillNo(soMaster.getBillNo());
//        }
        inventoryTransact.setBillNo(pickTask.getPickTaskCode());

        //Step2.保存，返回
        inventoryTransactService.save(inventoryTransact);
        return inventoryTransact;
    }


    /**
     * 根据可用库存，分配生成拣货任务
     *
     * @param soDetail      SO明细
     * @param inventoryDtos 可用库存
     */
    private void createPickTask(SoDetailDto soDetail, List<InventorySelectDto> inventoryDtos) {
        InventoryQuantity:
        for (InventorySelectDto inventorySelectDto : inventoryDtos) {
            Double canBeQuantity = inventorySelectDto.getQuantity() - inventorySelectDto.getAllotQuantity() - inventorySelectDto.getFreezeQuantity();
            //新建拣货任务
            PickTask pickTask = new PickTask(soDetail.getSoDetailId(), soDetail.getSoMasterId(), soDetail.getWareId(),
                    soDetail.getWareName(), soDetail.getOrganizationId(), soDetail.getOrganizationName(),
                    inventorySelectDto.getAreaCode(), inventorySelectDto.getAreaName(), inventorySelectDto.getShelfCode(),
                    inventorySelectDto.getShelfName(), inventorySelectDto.getCellCode(), inventorySelectDto.getCellName(),
                    inventorySelectDto.getItemCode(), inventorySelectDto.getItemName(), inventorySelectDto.getBatchId(),
                    inventorySelectDto.getBatchName(), inventorySelectDto.getBoxCode(), inventorySelectDto.getLpn(),
                    soDetail.getPackDetailId(), soDetail.getPackDescribe(), 0.0, 0,
                    inventorySelectDto.getInventoryId(), 2,
                    inventorySelectDto.getImgUrl()
            );

            //判断可分配数量
            //1)可分配数量 大于出库任务明细待分配数量 出库任务明细分配完毕
            //2)可分配数量不够完全分配  则将可分配数量全部分配出去
            if (canBeQuantity >= (soDetail.getOrderQuantity() - soDetail.getAllottedQuantity())) {
                pickTask.setPickQuantity(soDetail.getOrderQuantity() - soDetail.getAllottedQuantity());
                //记录库存已分配数量
                inventorySelectDto.setAllotQuantity(pickTask.getPickQuantity() + inventorySelectDto.getAllotQuantity());
                //记录出库任务的已分配数量
                soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() + pickTask.getPickQuantity());
                inventorySelectDto.setTransRatio(1.0);
                inventoryService.updateById(inventorySelectDto);
                save(pickTask);
                break InventoryQuantity;
            } else {
                double quantity = inventorySelectDto.getQuantity() - inventorySelectDto.getAllotQuantity() - inventorySelectDto.getFreezeQuantity();
                if (quantity > 0) {
                    pickTask.setPickQuantity(quantity);
                    inventorySelectDto.setAllotQuantity(inventorySelectDto.getAllotQuantity() + quantity);
                    soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() + quantity);
                    inventorySelectDto.setTransRatio(1.0);
                    inventoryService.updateById(inventorySelectDto);
                    save(pickTask);
                }
            }
        }

        //回写SO状态
        Double orderQuantity = soDetail.getOrderQuantity();
        Double allottedQuantity = soDetail.getAllottedQuantity();

        if (orderQuantity > allottedQuantity) {
            soDetail.setState(1);
        } else if (orderQuantity.equals(allottedQuantity)) {
            soDetail.setState(2);
        }
        soDetailService.updateById(soDetail);

        SoMaster soMaster = soMasterService.findBy("bill_no", soDetail.getBillNo());
        List<SoDetail> list = soDetailService.findByBillNo(soDetail.getBillNo());
        Boolean isEnd = true;
        for (SoDetail detail : list
        ) {
            if (detail.getOrderQuantity() > detail.getAllottedQuantity()) {
//                isEnd = false;  //只要库存足够,永远判断已分配   2022/5/25 22:14 徐
                isEnd = true;
                break;
            }
        }
        if (isEnd) {
            soMaster.setState(WareTaskConstant.SO_STATE_ASSIGNED); //全部分配
        } else {
            soMaster.setState(WareTaskConstant.SO_STATE_OUTOFSTOCK); //部分分配 缺货
            // cancelPickTask(soMaster.getBillNo());
        }
        soMasterService.updateById(soMaster);
    }

    private void cancelPickTask(String billNo) {
        List<SoDetail> soDetails = soDetailService.findByBillNo(billNo);
        for (SoDetail soDetail : soDetails) {
            if (soDetail.getState() == 0) {
                return;
            }
        }
        PickTaskCriteria criteria = new PickTaskCriteria();
        criteria.setBillNo(billNo);
        criteria.setState(0);
        List<PickTaskDto> tasks = pickTaskMapper.findList(criteria);
        for (PickTaskDto pickTask : tasks) {
            Integer inventoryId = pickTask.getInventoryId();
            Inventory inventory = inventoryService.getById(inventoryId);
            Double quantity = pickTask.getPickQuantity();
            inventory.setAllotQuantity(inventory.getAllotQuantity() - quantity);
            inventoryService.updateById(inventory);
            super.removeById(pickTask.getPickTaskId());
        }
        for (SoDetail soDetail : soDetails) {
            soDetail.setAllottedQuantity(0.0);
            soDetail.setState(0);
            soDetailService.updateById(soDetail);
        }

    }


}
